/**
 * <copyright> 
 *
 * Copyright (c) 2008 itemis AG and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: 
 *   itemis AG - Initial API and implementation
 *
 * </copyright>
 *
 */
package com.rd.emf.geneditor.view.editors.generic.binding;

import java.awt.TextArea;
import java.util.List;
import java.util.Map;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.databinding.edit.EMFEditObservables;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.impl.EEnumImpl;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.SimpleContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;

import com.rd.emf.geneditor.EMFGenericEditorPlugin;
import com.rd.emf.geneditor.model.OawFacade;
import com.rd.emf.geneditor.view.editors.generic.ProposalCreator;
import com.rd.xsd.common.CommonPackage;

/**
 * @author Dennis Huebner
 * 
 */
public class EmfSwtBindingFactory {

	private Composite parent = null;
	private FormToolkit toolkit = null;
	private final EObject owner;
	private final EditingDomain domain;
	private final EMFDataBindingContext edbc;
	private final AdapterFactory adapterFactory;
	private final ProposalCreator proposalcreator;
	private CheckboxTableViewer checkboxTableViewer;
	private Map<String, EObject> optionItems;

	public EmfSwtBindingFactory(AdapterFactory adapterFactory, EditingDomain domain, EObject owner, Composite parent,
			FormToolkit toolkit, OawFacade facade) {
		this.adapterFactory = adapterFactory;
		this.edbc = new EMFDataBindingContext();
		this.domain = domain;
		this.proposalcreator = new ProposalCreator(domain, facade);
		this.owner = owner;
		this.parent = parent;
		this.toolkit = toolkit;
	}

	public Control create(EObject eObject) {
		Control retVal = null;
		if (eObject instanceof EStructuralFeature) {
			retVal = createForEStructuralFeature((EStructuralFeature) eObject);
		}
		return retVal;
	}

	private Control createForEStructuralFeature(EStructuralFeature feature) {
		Control retVal = null;
		if (feature.isMany()) {
			retVal = createList(feature);
		} else {
			retVal = createControl(feature);
		}
		prepareControl(feature, retVal);
		return retVal;
	}

	private Control createList(EStructuralFeature feature) {
		IObservableList source = EMFEditObservables.observeList(domain, owner, feature);

		List<?> choice = proposalcreator.proposals(owner, feature);
		MultipleFeatureControl mfc = new MultipleFeatureControl(parent, toolkit, new AdapterFactoryLabelProvider(
				adapterFactory), owner, feature, choice);

		IObservableList target = ViewersObservables.observeMultiSelection(mfc.getInternalSelectionProvider());
		Binding binding = edbc.bindList(target, source, null, null);
		binding.updateModelToTarget();
		return mfc;
	}

	private Control createControl(final EStructuralFeature feature) {
		Control retVal = null;

		IObservableValue source = EMFEditObservables.observeValue(domain, owner, feature);
		IObservableValue target = null;
		Registry registry = EPackage.Registry.INSTANCE;
		registry.toString();

		if (feature instanceof EReference) {
			EReference eRef = ((EReference) feature);

			Class<? extends EReference> clazz = eRef.getClass();
			EGenericType eGenType = eRef.getEGenericType();
			EClassifier eClassifier = eRef.getEType();
			EClass eClass = eRef.getEReferenceType();

			System.out.println("eRef.toString(): " + eRef.toString());
			System.out.println("eRef.getClass(): " + clazz.toString());
			System.out.println("eRef.getEGenericType(): " + eGenType.toString());
			System.out.println("eRef.getEType(): " + eClassifier.toString());
			System.out.println("eRef.getEReferenceType(): " + eClass.toString());
			System.out.println("CommonPackage.eINSTANCE.getCheckList(): " + CommonPackage.eINSTANCE.getCheckList());
			System.out.println("CommonPackage.eINSTANCE.getTextArea(): " + CommonPackage.eINSTANCE.getTextArea());
			boolean isSuperType = CommonPackage.eINSTANCE.getTextArea().isSuperTypeOf(eRef.getEReferenceType());
			System.out.println(" ### isSuperTypeOf: " + isSuperType);

			System.out.println();
			System.out.println();

		}
		if (feature.getEType().equals(EcorePackage.eINSTANCE.getEBoolean())
				|| feature.getEType().equals(EcorePackage.Literals.EBOOLEAN_OBJECT)) {
			Button b = toolkit.createButton(parent, "", SWT.CHECK);
			target = SWTObservables.observeSelection(b);
			retVal = b;
			edbc.bindValue(target, source, null, null);
		} else if (feature instanceof TextArea) {
			Text t = toolkit.createText(parent, "", SWT.MULTI);
			target = SWTObservables.observeText(t, SWT.Modify);
			retVal = t;
			edbc.bindValue(target, source, null, null);
		} else if (feature.getEType() instanceof EEnumImpl) {
			ComboViewer combo = new ComboViewer(parent, SWT.READ_ONLY);
			toolkit.adapt(combo.getCombo());
			combo.setContentProvider(new ArrayContentProvider());
			combo.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));
			combo.setInput(proposalcreator.proposals(owner, feature));
			target = ViewersObservables.observeSingleSelection(combo);
			retVal = combo.getCombo();
			edbc.bindValue(target, source, null, null);
		} else if (feature.getEType().getName().equals("Boolean")) {
			Button button = new Button(parent, SWT.CHECK);
			target = SWTObservables.observeSelection(button);
			retVal = button;
			edbc.bindValue(target, source, null, null);
		} else {
			Text t = toolkit.createText(parent, new String());
			t.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
			List<?> proposals = proposalcreator.proposals(owner, feature);
			if (proposals != null && !proposals.isEmpty()) {
				ControlDecoration field = new ControlDecoration(t, SWT.BORDER);
				FieldDecoration requiredFieldIndicator = FieldDecorationRegistry.getDefault().getFieldDecoration(
						FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
				field.setImage(requiredFieldIndicator.getImage());
				field.setDescriptionText(requiredFieldIndicator.getDescription());
				KeyStroke keyStroke = null;
				String string = new String();
				try {
					string = "Ctrl+Space";
					keyStroke = KeyStroke.getInstance(string);
				} catch (ParseException e) {
					EMFGenericEditorPlugin.getDefault().getLog().log(
							new Status(IStatus.ERROR, EMFGenericEditorPlugin.PLUGIN_ID, "Error while parse: " + string,
									e));
				}
				new ContentProposalAdapter(t, new TextContentAdapter(), new SimpleContentProposalProvider(proposals
						.toArray(new String[] {})), keyStroke, null);
			}
			target = SWTObservables.observeText(t, SWT.Modify);
			retVal = t;
			edbc.bindValue(target, source, null, null);
		}

		return retVal;
	}

	private void prepareControl(EStructuralFeature f, Control c) {
		c.setEnabled(f.isChangeable());
		c.setData("EStructuralFeature", f);
		c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
	}

	public void dispose() {
		edbc.dispose();
		parent.dispose();
	}

}
